/*
 * Copyright (c) 2018 - 2028. www.vtuzx.com Inc. All Rights Reserved
 */
package com.vtuzx.kingdee.xqc_api.service.impl;

import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import com.vtuzx.core.VtuzxException;
import com.vtuzx.core.bean.dto.VtuzxMap;
import com.vtuzx.core.bean.dto.VtuzxPage;
import com.vtuzx.core.bean.dto.VtuzxToken;
import com.vtuzx.core.constant.IVtuzxConst;
import com.vtuzx.core.file.excel.VtuzxExcel;
import com.vtuzx.core.file.excel.VtuzxExcelCell;
import com.vtuzx.core.file.excel.VtuzxExcelRow;
import com.vtuzx.core.file.excel.VtuzxExcelSheet;
import com.vtuzx.core.utils.VtuzxUtil;
import com.vtuzx.fast.utils.FastUtil;
import com.vtuzx.kingdee.xqc_api.service.IXqcConfigService;
import com.vtuzx.kingdee.xqc_api.service.IXqcInventoryService;
import com.vtuzx.kingdee.xqc_api.service.IXqcOtherService;
import com.vtuzx.kingdee.xqc_api.service.IXqcSyncKingdeeOrderService;
import com.vtuzx.kingdee.xqc_core.bean.VtuzxArrayList;
import com.vtuzx.kingdee.xqc_core.bean.xqc.BillMaterial;
import com.vtuzx.kingdee.xqc_core.bean.xqc.BillMaterialBox;
import com.vtuzx.kingdee.xqc_core.constant.BillEvent;
import com.vtuzx.kingdee.xqc_core.constant.BillStatus;
import com.vtuzx.kingdee.xqc_core.constant.BillType;
import com.vtuzx.kingdee.xqc_core.constant.IXqcConst;
import com.vtuzx.kingdee.xqc_core.dao.*;
import com.vtuzx.web.bean.VtuzxDownloadBean;
import com.vtuzx.web.dao.mongo.CustomerDao;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 采购服务
 */
@Service
public class XqcOtherServiceImpl implements IXqcOtherService {

    /** Logger */
    private static final Logger _logger = LoggerFactory.getLogger(XqcOtherServiceImpl.class);

    @Autowired
    private OtherInDao otherInDao;

    @Autowired
    private OtherInDetailDao otherInDetailDao;

    @Autowired
    private OtherOutDetailDao otherOutDetailDao;
    /**
     * 仓库
     */
    @Autowired
    private StockDao stockDao;

    @Autowired
    private OtherInDetailBoxDao otherInDetailBoxDao;

    @Autowired
    private OtherColDao otherColDao;

    @Autowired
    private OtherOutDao otherOutDao;

    @Autowired
    private TestRoomDao testRoomDao;

    @Autowired
    private OtherColDetailDao otherColDetailDao;

    @Autowired
    private CustomerDao customerDao;

    @Autowired
    private MaterialDao materialDao;

    @Autowired
    private SupplierDao supplierDao;

    @Autowired
    private IXqcInventoryService inventoryService;

    @Autowired
    private XqcInventoryServiceImpl xqcInventoryService;

    @Autowired
    private IXqcConfigService configService;

    @Autowired
    private SyncOrderDao syncOrderDao;

    @Autowired
    private IXqcSyncKingdeeOrderService syncKingdeeOrderService;


    @Override
    public void bindOtherOutBoxRfid(String boxNo, String rfid) throws VtuzxException {
        Document boxDoc = otherColDetailDao.findOne(Criteria.where("boxNo").is(boxNo).and("inStock").ne(true));
        if (boxDoc == null) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_exist, boxNo);
        }
        String billNo = VtuzxUtil.getString(boxDoc, "billNo");
        Document otherColDoc = otherColDao.findOne(Criteria.where("billNo").is(billNo));
        if (otherColDoc == null) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_exist, boxNo);
        }
        String status = VtuzxUtil.getString(otherColDoc, "status");
        if (!BillStatus.Audit.hit(status)) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_audit, boxNo);
        }
        Criteria lastOtherColBindRfid = Criteria.where("rfid").is(rfid).and("inStock").ne(true);
        Document lastOtherColDetail = otherColDetailDao.findOne(lastOtherColBindRfid);
        if(lastOtherColDetail != null) {
            otherColDetailDao.updateByIdRedirect(lastOtherColDetail.getObjectId(IVtuzxConst.Key__id), new Document("$unset", new Document("rfid", 1)));
            otherColDao.updateOneRedirect(Criteria.where("billNo").is(VtuzxUtil.getString(lastOtherColDetail, "billNo")), new Document("$inc", new Document("bindBoxCount", -1)));
        }
        otherColDetailDao.updateById(boxDoc.getObjectId(IVtuzxConst.Key__id), new Document("rfid", rfid));
        if (VtuzxUtil.isEmpty(VtuzxUtil.getString(boxDoc, "rfid"))) {
            otherColDao.updateByIdRedirect(otherColDoc.getObjectId(IVtuzxConst.Key__id), new Document("$inc", new Document("bindBoxCount", 1)));
        }
    }

    @Override
    public VtuzxMap getOtherOutMaterialForBind(String boxNo) throws VtuzxException {
        Document boxDoc = otherColDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
        if (boxDoc == null) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_exist, boxNo);
        }
        boolean inStock = VtuzxUtil.getBoolean(boxDoc, "inStock");
        if (inStock) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_in_stock, boxNo);
        }
        String billNo = VtuzxUtil.getString(boxDoc, "billNo");
        Document otherColDoc = otherColDao.findOne(Criteria.where("billNo").is(billNo));
        if (otherColDoc == null) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_exist, boxNo);
        }
        String status = VtuzxUtil.getString(otherColDoc, "status");
        if (!BillStatus.Audit.hit(status)) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_audit, boxNo);
        }
        return new VtuzxMap("materialNo", VtuzxUtil.getString(otherColDoc, "materialNo"))
                .append("materialName", VtuzxUtil.getString(otherColDoc, "materialName"))
                .append("materialSpec", VtuzxUtil.getString(otherColDoc, "materialSpec"))
                .append("batchNo", VtuzxUtil.getString(otherColDoc, "batchNo"))
                .append("unit", VtuzxUtil.getString(otherColDoc, "unit"))
                .append("count", VtuzxUtil.getDouble(boxDoc, "count"))
                .append("supplierName", VtuzxUtil.getString(otherColDoc, "supplierName"))
                .append("instockDate", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(otherColDoc, "createTime")))
                .append("produceDate", VtuzxUtil.getString(otherColDoc, "produceDate"))
                .append("exp", VtuzxUtil.getInt(otherColDoc, "exp"));
    }

    @Override
    public void saveUserOtherIn(ObjectId _userId, String userName, Map<String, Object> param) throws VtuzxException {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String remark = VtuzxUtil.getString(param, "remark");
        String billNo = IXqcConst.createBillNo(BillType.QTRK);
        String type = VtuzxUtil.getString(param,"type");
        String taskBillNo = VtuzxUtil.getString(param,"taskBillNo");
        String otherOutNo = VtuzxUtil.getString(param,"outNo");
        if ("沫沫".equals(type)){
            if (VtuzxUtil.isEmpty(taskBillNo)){
                throw new VtuzxException("沫沫必填任务号");
            }
        }
        Criteria opCond = Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true);
        Iterator<Document> detailItr = otherInDetailDao.findList(opCond, null, 0, 0);
        int boxCount = 0;
        double count = 0d;
        while(detailItr.hasNext()) {
            Document detail = detailItr.next();
            boxCount++;
            count += VtuzxUtil.getDouble(detail, "count");
        }
        //合拆箱类型的入库单数量要与对应的出库单数量相等
        if ("合-拆箱".equals(type)){
            DecimalFormat df = new DecimalFormat("#.00");
            Document otherOutDoc = otherOutDao.findOne(Criteria.where("billNo").is(otherOutNo));
            double otherOutCount = VtuzxUtil.getDouble(otherOutDoc,"count");
            String formatcount = df.format(count);
            String formatOther = df.format(otherOutCount);
            if ( !formatcount.equals(formatOther) ){
                throw new VtuzxException("无法入库,入库数量要与出库数量一致");
            }
        }
        Document otherInDoc = new Document("billNo", billNo)
                .append("stockNo", stockNo)
                .append("boxCount", boxCount)
                .append("count", count)
                .append("remark", remark)
                .append("taskBillNo",taskBillNo)
                .append("otherOutNo",otherOutNo)
                .append("type",type)//新增入库类型
                .append("isPrint","unSeal")//是否打印
                .append("status", BillStatus.Save.toString());
        otherInDao.insertBill(_userId, userName, otherInDoc);
        try {
            Document detailUpdateVal = new Document("$set", new Document("billNo", billNo));
            detailUpdateVal.append("$unset", new Document("isTemp", 1));
            otherInDetailDao.updateManyRedirect(opCond, detailUpdateVal);
            otherInDetailBoxDao.updateManyRedirect(opCond, detailUpdateVal);
            auditOtherInOrder(_userId, userName, stockNo, billNo);
            //如果其他出库单号不为空，并且类型为合拆箱传批号调整单
            //需要判断出库和入库的品是否一样,一样的传批号调整单,不一样的不传
            Boolean flag = otherMaterial(billNo,otherOutNo);
            if (!VtuzxUtil.isEmpty(otherOutNo) && "合-拆箱".equals(type) && flag){
                syncKingdeeOrderService.syncTransferDirectOther(_userId,userName,billNo,otherOutNo,"pda");
            }
        } catch(Exception e) {
            Criteria rollbackCond = Criteria.where("billNo").is(billNo);
            otherInDao.deleteOne(rollbackCond);
            otherInDetailDao.updateManyRedirect(rollbackCond,
                    new Document("$set", new Document("isTemp", true)).append("$unset", new Document("billNo", 1)));
            otherInDetailBoxDao.updateManyRedirect(rollbackCond,
                    new Document("$set", new Document("isTemp", true)).append("$unset", new Document("billNo", 1)));
            _logger.info(e.getMessage());
        }
    }



    /**
     * 其他入库单审批
     *
     * @param _userId 用户ID
     * @param userName 用户名
     * @param stockNo 仓库编码
     * @param billNo 单据号
     * @throws VtuzxException 异常处理
     */
    public void auditOtherInOrder(ObjectId _userId, String userName, String stockNo, String billNo) throws VtuzxException {
        Criteria getCond = Criteria.where("billNo").is(billNo);
        Iterator<Document> otherInDetailItr = otherInDetailDao.findList(getCond, null, 0, 0);
        Iterator<Document> otherInDetailBoxItr = otherInDetailBoxDao.findList(getCond, null, 0, 0);
        List<Document> otherInDetailBoxList = new ArrayList<>();
        List<String> colBoxNoList = new ArrayList<>();
        while(otherInDetailBoxItr.hasNext()) {
            Document document = otherInDetailBoxItr.next();
            String boxNo = VtuzxUtil.getString(document, "boxNo");
            colBoxNoList.add(boxNo);
            otherInDetailBoxList.add(document);
        }

        VtuzxMap updateColBillMap = new VtuzxMap();
        Iterator<Document> purColDetailItr = otherColDetailDao.findList(Criteria.where("boxNo").in(colBoxNoList), null, 0, 0);
        while (purColDetailItr.hasNext()) {
            Document purColDetailDoc = purColDetailItr.next();
            double count = VtuzxUtil.getDouble(purColDetailDoc, "count");
            String colBillNo = VtuzxUtil.getString(purColDetailDoc, "billNo");
            VtuzxMap updateColBill = VtuzxUtil.getObject(updateColBillMap, colBillNo);
            if (VtuzxUtil.isEmpty(updateColBill)) {
                VtuzxMap smallColBillMap = new VtuzxMap();
                smallColBillMap.append("count", count).append("boxCount", 1);
                updateColBillMap.append(colBillNo, smallColBillMap);
            } else {
                double sCount = VtuzxUtil.getDouble(updateColBill, "count");
                int sBoxCount = VtuzxUtil.getInt(updateColBill, "boxCount");
                updateColBillMap.append(colBillNo, new VtuzxMap("count", sCount + count).append("boxCount", sBoxCount + 1));
            }

        }

        List<BillMaterial> otherInDetailList = new ArrayList<>();
        List<String> boxNoList = new ArrayList<>();
        while(otherInDetailItr.hasNext()) {
            Document otherInDetail = otherInDetailItr.next();
            BillMaterial billMaterial = new BillMaterial();
            ObjectId _otherInDetailId = otherInDetail.getObjectId(IVtuzxConst.Key__id);
            billMaterial.setMaterialNo(VtuzxUtil.getString(otherInDetail, "materialNo"));
            billMaterial.setUnit(VtuzxUtil.getString(otherInDetail, "unit"));
            billMaterial.setBatchNo(VtuzxUtil.getString(otherInDetail, "batchNo"));
            billMaterial.setProduceDate(VtuzxUtil.getString(otherInDetail, "produceDate"));
            billMaterial.setExp(VtuzxUtil.getInt(otherInDetail, "exp"));
            List<BillMaterialBox> boxList = new ArrayList<>();
            for(Document boxDoc: otherInDetailBoxList) {
                String barcodeType = VtuzxUtil.getString(boxDoc, "barcodeType");
                ObjectId _detailId = VtuzxUtil.getObject(boxDoc, "_detailId");
                if (_otherInDetailId.equals(_detailId)) {
                    BillMaterialBox box = new BillMaterialBox();
                    String boxNo = VtuzxUtil.getString(boxDoc, "boxNo");
                    box.setBoxNo(boxNo);
                    box.setRfid(VtuzxUtil.getString(boxDoc, "rfid"));
                    box.setCount(VtuzxUtil.getDouble(boxDoc, "count"));
                    box.setLocationNo(VtuzxUtil.getString(otherInDetail, "locationNo"));
                    boxList.add(box);
                    if (!"BC".equals(barcodeType)) {
                        boxNoList.add(boxNo);
                    }
                }
                billMaterial.setBoxList(boxList);
            }
            otherInDetailList.add(billMaterial);
        }
        otherInDao.audit(_userId, userName, billNo);

        Document otherInDoc = otherInDao.findOne(Criteria.where("billNo").is(billNo));
        String type = VtuzxUtil.getString(otherInDoc,"type");
        if (!"沫沫".equals(type) && !"合-拆箱".equals(type)){//沫沫和合-拆箱的不传金蝶
            try {
                syncKingdeeOrderService.syncOtherInOrder(_userId, userName, billNo, "pda");
            } catch (Exception e) {
                _logger.error(e.getMessage(), e);
            }
        }

        // 更新收货单入库状态
        if (!VtuzxUtil.isEmpty(boxNoList)) {
            try {
                UpdateResult updRes = otherColDetailDao.updateMany(Criteria.where("boxNo").in(boxNoList).and("inStock").ne(true),
                        new Document("otherInBillNo", billNo).append("otherInTime", new Date()).append("inStock", true));
                if (updRes.getModifiedCount() != boxNoList.size()) {
                    throw new VtuzxException(IXqcConst.Msg_E_XQC_stock_pur_col_in_stock);
                }
            } catch(Exception e) {
                otherColDetailDao.updateManyRedirect(Criteria.where("boxNo").in(boxNoList),
                        new Document("$unset", new Document("otherInBillNo", 1).append("otherInTime", 1).append("inStock", 1)));
                otherInDao.unaudit(billNo);
                throw e;
            }
        }
        // 更新即时库存
        try {
            inventoryService.addInventory(_userId, userName, BillEvent.Audit, BillType.QTRK, stockNo, billNo, otherInDetailList);
        } catch(Exception e) {
            otherInDao.unaudit(billNo);
            if (!VtuzxUtil.isEmpty(boxNoList)) {
                otherColDetailDao.updateManyRedirect(Criteria.where("boxNo").in(boxNoList),
                        new Document("$unset", new Document("otherInBillNo", 1).append("otherInTime", 1).append("inStock", 1)));
            }
            throw e;
        }

        //做收货单的已入库数量重量的反写
        updateColBillMap.forEach((k, v) -> {
            VtuzxMap map = (VtuzxMap) v;
            double sCount = VtuzxUtil.getDouble(map, "count");
            int sBoxCount = VtuzxUtil.getInt(map, "boxCount");
            otherColDao.updateOneRedirect(Criteria.where("billNo").is(k), new Document("$inc", new Document("inStockCount", sCount).append("inStockBoxCount", sBoxCount)));
        });


//        try {
//            Map<String, Object> data = new HashMap<>();
//            data.put("billNo", billNo);
//            data.put("source", "PDA");
//            data.put("historyDoc", historyDoc);
//            syncKingdeeOrderService.syncOtherInOrder(_userId, userName, data);
//        } catch (Exception e) {
//            historyDoc.append("otherInStock", false).append("message", e.getMessage()).append("success", false);
//            syncOrderDao.insertOne(historyDoc);
//            throw e;
//        }
    }

    @Override
    public VtuzxMap addUserOtherInMaterialBoxList(ObjectId _userId, String userName, String stockNo, String locationNo, List<Map<String, Object>> boxList) {
        for(Map<String, Object> box: boxList) {
            String boxNo = VtuzxUtil.getString(box, "boxNo");
            double count = VtuzxUtil.getDouble(box, "count");
            try {
                VtuzxMap otherColDetail = getOtherColMaterial(boxNo);
                addUserOtherInMaterialBoxInner(otherColDetail, _userId, userName, stockNo, locationNo, boxNo, count);
            } catch(Exception e) {
                _logger.info("addUserOtherInMaterialBoxList error:" + e.getMessage());
            }
        }
        return getUserOtherInMaterial(_userId, stockNo);
    }

    @Override
    public VtuzxMap addUserOtherInMaterialBox(ObjectId _userId, String userName, String stockNo, String locationNo, String boxNo, double count) throws VtuzxException {
        VtuzxMap otherColDetail = getOtherColMaterial(boxNo);
        ObjectId _detailId = addUserOtherInMaterialBoxInner(otherColDetail, _userId, userName, stockNo, locationNo, boxNo, count);
        Document otherInDetailDoc = otherInDetailDao.findById(_detailId);
        return new VtuzxMap("boxCount", VtuzxUtil.getObject(otherInDetailDoc, "boxCount"))
                .append("count", VtuzxUtil.getObject(otherInDetailDoc, "count"))
                .append("colBoxCount", VtuzxUtil.getObject(otherColDetail, "boxCount"))
                .append("colCount", VtuzxUtil.getObject(otherColDetail, "count"));
    }

    /**
     * 采购入库增加临时箱号内部方法
     * @param otherColDetail 收货单详细
     * @param _userId 用户ID
     * @param userName 用户名
     * @param stockNo 仓库编码
     * @param locationNo 仓位编码
     * @param boxNo 箱号
     * @param count 数量
     * @return 信息ID
     * @throws VtuzxException 异常处理
     */
    public ObjectId addUserOtherInMaterialBoxInner(VtuzxMap otherColDetail, ObjectId _userId, String userName, String stockNo, String locationNo, String boxNo, double count) throws VtuzxException {

        String barcodeType = VtuzxUtil.getString(otherColDetail, "barcodeType");
        if ("BC".equals(barcodeType)) {
            boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
            boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
            boxNo = boxNo.substring(0, boxNo.lastIndexOf("|;"));
            boxNo = boxNo + "|;batch";
        } else {
            Document scanBoxDoc = otherInDetailBoxDao.findOne(Criteria.where("boxNo").is(boxNo));
            if (scanBoxDoc != null) {
                throw new VtuzxException("箱号已入库!");
            }
        }

        String billNo = VtuzxUtil.getString(otherColDetail, "billNo");
        String materialNo = VtuzxUtil.getString(otherColDetail, "materialNo");
        String materialName = VtuzxUtil.getString(otherColDetail, "materialName");
        String materialSpec = VtuzxUtil.getString(otherColDetail, "materialSpec");
        String batchNo = VtuzxUtil.getString(otherColDetail, "batchNo");
        String rfid = VtuzxUtil.getString(otherColDetail, "rfid");
        String produceDate = VtuzxUtil.getString(otherColDetail, "produceDate");
        int exp = VtuzxUtil.getInt(otherColDetail, "exp");
        String unit = VtuzxUtil.getString(otherColDetail, "unit");
        int colBoxCount = VtuzxUtil.getInt(otherColDetail, "boxCount");
        double colCount = VtuzxUtil.getDouble(otherColDetail, "countTotal");
        Criteria detailCond = Criteria.where("_createUserId").is(_userId);
        detailCond.and("isTemp").is(true);
        detailCond.and("stockNo").is(stockNo);
        detailCond.and("locationNo").is(locationNo);
        detailCond.and("materialNo").is(materialNo);
        detailCond.and("batchNo").is(batchNo);
        detailCond.and("produceDate").is(produceDate);
        detailCond.and("exp").is(exp);
        detailCond.and("unit").is(unit);
        Document detail = otherInDetailDao.findOne(detailCond);

        double nowColCount = 0.0;
        int nowColBoxCount = 0;
        if ("BC".equals(barcodeType)) {
            nowColCount = count;
            nowColBoxCount = 1;
//            if (detail != null) {
//                nowColCount += VtuzxUtil.getDouble(detail, "count");
//                nowColBoxCount += VtuzxUtil.getInt(detail, "boxCount");
//            }
        } else {
            Iterator<Document> otherColDetailItr = otherColDetailDao.findList(Criteria.where("billNo").is(billNo), new Document("createTime", -1), 0, 0);
            while (otherColDetailItr.hasNext()) {
                Document otherColDetailDoc = otherColDetailItr.next();
                boolean inStock = VtuzxUtil.getBoolean(otherColDetailDoc, "inStock");
                double otherColCount = VtuzxUtil.getDouble(otherColDetailDoc, "count");
                if (!inStock) {
                    nowColCount += otherColCount;
                    nowColBoxCount++;
                }
            }
        }
        Document updateVal = new Document();

        if (detail == null) {
            updateVal.append("isTemp", true);
            updateVal.append("billNo", billNo);
            updateVal.append("stockNo", stockNo);
            updateVal.append("locationNo", locationNo);
            updateVal.append("materialNo", materialNo);
            updateVal.append("materialName", materialName);
            updateVal.append("materialSpec", materialSpec);
            updateVal.append("unit", unit);
            updateVal.append("batchNo", batchNo);
            updateVal.append("produceDate", produceDate);
            updateVal.append("exp", exp);
            updateVal.append("_createUserId", _userId);
            updateVal.append("createUserName", userName);
            updateVal.append("boxCount", 1);
            updateVal.append("count", count);
            updateVal.append("colCount", colCount);
            updateVal.append("colBoxCount", colBoxCount);
            updateVal.append("nowColCount", nowColCount);
            updateVal.append("nowColBoxCount", nowColBoxCount);
        } else {
            updateVal = new Document("$inc", new Document("boxCount", 1).append("count", count)).append("$set", new Document("nowColCount", nowColCount).append("nowColBoxCount", nowColBoxCount));
        }
        ObjectId _detailId;
        if (detail == null) {
            _detailId = otherInDetailDao.insertOne(updateVal);
        } else {
            _detailId = VtuzxUtil.getObject(detail, IVtuzxConst.Key__id);
            otherInDetailDao.updateByIdRedirect(_detailId, updateVal);
        }
        Document detailBox = new Document();
        detailBox.append("isTemp", true);
        detailBox.append("_detailId", _detailId);
        detailBox.append("boxNo", boxNo);
        detailBox.append("rfid", rfid);
        detailBox.append("count", count);
        detailBox.append("unit", unit);
        detailBox.append("_createUserId", _userId);
        detailBox.append("createUserName", userName);
        detailBox.append("stockNo", stockNo);
        detailBox.append("barcodeType", barcodeType);
        otherInDetailBoxDao.insertOne(detailBox);
        return _detailId;
    }

    @Override
    public VtuzxMap deleteUserOtherInMaterialBox(ObjectId _userId, String id) {
        Document otherInDetailBoxDoc = otherInDetailBoxDao.findOne(Criteria.where("_detailId").is(FastUtil.convertId(id)));
        ObjectId _detailId = VtuzxUtil.getObject(otherInDetailBoxDoc, "_detailId");
        otherInDetailBoxDao.deleteById(FastUtil.convertId(id));
        Iterator<Document> otherInDetailBoxItr = otherInDetailBoxDao.findList(Criteria.where("_detailId").is(_detailId), null, 0, 0);
        int boxCount = 0;
        double total = 0;
        while(otherInDetailBoxItr.hasNext()) {
            Document doc = otherInDetailBoxItr.next();
            double otherInDetailBoxCount = VtuzxUtil.getDouble(doc, "count");
            total = otherInDetailBoxCount + total;
            boxCount++;
        }
        if (boxCount == 0 && total == 0) {
            otherInDetailDao.deleteById(_detailId);
        } else {
            otherInDetailDao.updateById(_detailId, new Document("boxCount", boxCount).append("count", total));
        }
        return new VtuzxMap("count", total).append("boxCount", boxCount);
    }

    @Override
    public void deleteUserOtherInMaterial(ObjectId _userId, String id) {
        otherInDetailDao.deleteById(FastUtil.convertId(id));
        otherInDetailBoxDao.deleteMany(Criteria.where("_detailId").is(FastUtil.convertId(id)));
    }

    @Override
    public void deleteUserOtherIn(ObjectId _userId, String stockNo) {
        Criteria cond = Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true);
        otherInDetailDao.deleteMany(cond);
        otherInDetailBoxDao.deleteMany(cond);
    }

    @Override
    public VtuzxMap updateUserOtherInMaterialBox(ObjectId _userId, String stockNo, String locationNo, String materialNo, String boxNo, double count) {
        Criteria cond = Criteria.where("_createUserId").is(_userId).and("boxNo").is(boxNo).and("isTemp").is(true);
        Document detailBoxDoc = otherInDetailBoxDao.findOne(cond);
        ObjectId _detailId = VtuzxUtil.getObject(detailBoxDoc, "_detailId");
        otherInDetailBoxDao.updateOne(cond, new Document("count", count));
        Iterator<Document> otherInDetailBoxItr = otherInDetailBoxDao.findList(Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true), new Document("stockNo", 1), 0, 0);
        int boxCount = 0;
        double total = 0;
        while(otherInDetailBoxItr.hasNext()) {
            Document doc = otherInDetailBoxItr.next();
            double otherInDetailBoxCount = VtuzxUtil.getDouble(doc, "count");
            total = otherInDetailBoxCount + total;
            boxCount++;
        }
        otherInDetailDao.updateById(_detailId, new Document("boxCount", boxCount).append("count", total));
        return new VtuzxMap("count", total).append("boxCount", boxCount);
    }

    @Override
    public VtuzxMap getUserOtherInMaterial(ObjectId _userId, String stockNo) {
        List<VtuzxMap> otherInDetailList = new ArrayList<>();
        Iterator<Document> otherInDetailItr = otherInDetailDao.findList(Criteria.where("_createUserId").is(_userId).and("stockNo").is(stockNo).and("isTemp").is(true), null, 0, 0);
        while (otherInDetailItr.hasNext()) {
            Document otherInDetailDoc = otherInDetailItr.next();
            VtuzxMap otherInDetailMap = new VtuzxMap(otherInDetailDoc);
            String id = VtuzxUtil.removeString(otherInDetailMap, IVtuzxConst.Key__id);
            String createUserId = VtuzxUtil.removeString(otherInDetailMap, "_createUserId");
            otherInDetailMap.append("id", id).append("createUserId", createUserId);
            otherInDetailList.add(otherInDetailMap);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, otherInDetailList);
    }

    @Override
    public VtuzxMap getUserOtherInMaterialBox(ObjectId _userId, String _detailId) {
        List<VtuzxMap> otherInDetailBoxList = new ArrayList<>();
        Iterator<Document> otherInDetailBoxItr = otherInDetailBoxDao.findList(Criteria.where("_createUserId").is(_userId).and("_detailId").is(new ObjectId(_detailId)), null, 0, 0);
        while (otherInDetailBoxItr.hasNext()) {
            Document otherInDetailBoxDoc = otherInDetailBoxItr.next();
            VtuzxMap boxMap = new VtuzxMap(otherInDetailBoxDoc);
            boxMap.remove(IVtuzxConst.Key_createTime);
            boxMap.remove(IVtuzxConst.Key_updateTime);
            boxMap.remove("_createUserId");
            boxMap.remove("createUserName");
            boxMap.remove("_updateUserId");
            boxMap.remove("updateUserName");
            boxMap.append("id", VtuzxUtil.removeString(boxMap, IVtuzxConst.Key__id));
            otherInDetailBoxList.add(boxMap);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, otherInDetailBoxList);
    }

    /*@Override
    public VtuzxMap getOtherInBill(ObjectId _userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String taskBillNo = VtuzxUtil.getString(param, "taskBillNo");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String boxNo = VtuzxUtil.getString(param, "boxNo");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        String remark = VtuzxUtil.getString(param,"remark");
        String otherOutNo = VtuzxUtil.getString(param,"otherOutNo");
        String isPrint = VtuzxUtil.getString(param, "isPrint");
        String type = VtuzxUtil.getString(param,"type");
        List<String> createTime = VtuzxUtil.getObject(param, "createTime");
        List<VtuzxMap> dataList = new ArrayList<>();
        Criteria cond = new Criteria();
        cond.and("count").ne(0);//数量等于零的不显示
        if (!VtuzxUtil.isEmpty(stockNo)) {
            cond.and("stockNo").regex(stockNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(type)) {
            cond.and("type").regex(type);
        }
        if(!VtuzxUtil.isEmpty(otherOutNo)){
            cond.and("otherOutNo").regex(otherOutNo);
        }
        if (!VtuzxUtil.isEmpty(isPrint)) {
            cond.and("isPrint").is(isPrint);
        }
        if (!VtuzxUtil.isEmpty(taskBillNo)) {
            cond.and("taskBillNo").regex(taskBillNo);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            String[] splitList = createUserName.split("，");
            if (splitList.length == 1) {
                cond.and("createUserName").regex(createUserName);
            } else {
                List<String> split = new ArrayList<>(Arrays.asList(splitList));//数组转list
                cond.and("createUserName").in(split);
            }
        }
        if (!VtuzxUtil.isEmpty(remark)){
            cond.and("remark").regex(remark);
        }
        if (!VtuzxUtil.isEmpty(createTime)) {
            cond.and("createTime").gte(VtuzxUtil.parseDate(createTime.get(0))).lte(VtuzxUtil.parseDate(createTime.get(1) + " 23:59:59"));
        }
        if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo) || !VtuzxUtil.isEmpty(boxNo)) {
            List<String> inBillNoList = new ArrayList<>();
            if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo)) {
                Criteria smallCond = new Criteria();
                if (!VtuzxUtil.isEmpty(materialNo)) {
                    smallCond.and("materialNo").is(materialNo);
                }
                if (!VtuzxUtil.isEmpty(batchNo)) {
                    smallCond.and("batchNo").regex(batchNo);
                }
                Iterator<Document> purInDetailItr = otherInDetailDao.findList(smallCond, null, 0, 0);
                while (purInDetailItr.hasNext()) {
                    Document purInDetailDoc = purInDetailItr.next();
                    String purInBillNo = VtuzxUtil.getString(purInDetailDoc, "billNo");
                    inBillNoList.add(purInBillNo);
                }
            }
            if (!VtuzxUtil.isEmpty(boxNo) ){
                if (inBillNoList.size()>0){
                    inBillNoList.clear();
                }
                Iterator<Document> boxItr = otherInDetailBoxDao.findList(Criteria.where("boxNo").is(boxNo),null, 0, 0);
                while (boxItr.hasNext()) {
                    Document boxDoc = boxItr.next();
                    inBillNoList.add(VtuzxUtil.getString(boxDoc, "billNo"));
                }
            }

            Iterator<Document> purInItr = otherInDao.findList(Criteria.where("billNo").in(inBillNoList), new Document("createTime",-1), 0, 0);
            while (purInItr.hasNext()) {
                Document purInDoc = purInItr.next();
                VtuzxMap purInMap = new VtuzxMap(purInDoc);
                purInMap.append("id", VtuzxUtil.removeString(purInMap, IVtuzxConst.Key__id));
                purInMap.append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(purInMap, "createTime")));
                dataList.add(purInMap);
            }
            return new VtuzxMap(IVtuzxConst.Key_data, dataList);
        }
        VtuzxPage page = otherInDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("status", VtuzxUtil.getString(doc, "status"))
                .append("stockNo", VtuzxUtil.getString(doc, "stockNo"))
                .append("remark", VtuzxUtil.getString(doc, "remark"))
                .append("auditTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "auditTime")))
                .append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "createTime")))
                .append("type",VtuzxUtil.getString(doc,"type"))
                .append("isPrint",VtuzxUtil.getString(doc,"isPrint"))
                .append("taskBillNo",VtuzxUtil.getString(doc,"taskBillNo"))
                .append("otherOutNo",VtuzxUtil.getString(doc,"otherOutNo"))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }*/
    @Override
    public VtuzxMap getOtherInBill(ObjectId _userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String taskBillNo = VtuzxUtil.getString(param, "taskBillNo");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String boxNo = VtuzxUtil.getString(param, "boxNo");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        String remark = VtuzxUtil.getString(param,"remark");
        String otherOutNo = VtuzxUtil.getString(param,"otherOutNo");
        String isPrint = VtuzxUtil.getString(param, "isPrint");
        String type = VtuzxUtil.getString(param,"type");
        List<String> createTime = VtuzxUtil.getObject(param, "createTime");
        Criteria cond = new Criteria();
        cond.and("count").ne(0);//数量等于零的不显示
        if (!VtuzxUtil.isEmpty(stockNo)) {
            cond.and("stockNo").regex(stockNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(type)) {
            cond.and("type").regex(type);
        }
        if(!VtuzxUtil.isEmpty(otherOutNo)){
            cond.and("otherOutNo").regex(otherOutNo);
        }
        if (!VtuzxUtil.isEmpty(isPrint)) {
            cond.and("isPrint").is(isPrint);
        }
        if (!VtuzxUtil.isEmpty(taskBillNo)) {
            cond.and("taskBillNo").regex(taskBillNo);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            String[] splitList = createUserName.split("，");
            if (splitList.length == 1) {
                cond.and("createUserName").regex(createUserName);
            } else {
                List<String> split = new ArrayList<>(Arrays.asList(splitList));//数组转list
                cond.and("createUserName").in(split);
            }
        }
        if (!VtuzxUtil.isEmpty(remark)){
            cond.and("remark").regex(remark);
        }
        if (!VtuzxUtil.isEmpty(createTime)) {
            cond.and("createTime").gte(VtuzxUtil.parseDate(createTime.get(0))).lte(VtuzxUtil.parseDate(createTime.get(1) + " 23:59:59"));
        }
        List<String> inBillNoList = new ArrayList<>();
        if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo) || !VtuzxUtil.isEmpty(boxNo)) {
            if (!VtuzxUtil.isEmpty(materialNo) || !VtuzxUtil.isEmpty(batchNo)) {
                Criteria smallCond = new Criteria();
                if (!VtuzxUtil.isEmpty(materialNo)) {
                    smallCond.and("materialNo").is(materialNo);
                }
                if (!VtuzxUtil.isEmpty(batchNo)) {
                    smallCond.and("batchNo").regex(batchNo);
                }
                Iterator<Document> purInDetailItr = otherInDetailDao.findList(smallCond, null, 0, 0);
                while (purInDetailItr.hasNext()) {
                    Document purInDetailDoc = purInDetailItr.next();
                    String purInBillNo = VtuzxUtil.getString(purInDetailDoc, "billNo");
                    inBillNoList.add(purInBillNo);
                }
            }
            if (!VtuzxUtil.isEmpty(boxNo) ){
                if (inBillNoList.size()>0){
                    inBillNoList.clear();
                }
                Iterator<Document> boxItr = otherInDetailBoxDao.findList(Criteria.where("boxNo").is(boxNo),null, 0, 0);
                while (boxItr.hasNext()) {
                    Document boxDoc = boxItr.next();
                    inBillNoList.add(VtuzxUtil.getString(boxDoc, "billNo"));
                }
            }

            //将子查询结果整合到主条件cond中
            if (!inBillNoList.isEmpty()) {
                cond.and("billNo").in(inBillNoList);
            } else {
                //子查询无结果直接返回空数据
                return new VtuzxMap(IVtuzxConst.Key_total, 0).append(IVtuzxConst.Key_data, new ArrayList<>());
            }
        }
        //统一使用cond进行分页查询
        VtuzxPage page = otherInDao.page(cond, new Document("createTime", -1), pageIndex, pageSize);
        List<VtuzxMap> dataList = page.iterator(doc -> new VtuzxMap("id", VtuzxUtil.getString(doc, IVtuzxConst.Key__id))
                .append("billNo", VtuzxUtil.getString(doc, "billNo"))
                .append("createUserName", VtuzxUtil.getString(doc, "createUserName"))
                .append("_createUserId", VtuzxUtil.getObject(doc, "_createUserId"))
                .append("boxCount", VtuzxUtil.getInt(doc, "boxCount"))
                .append("status", VtuzxUtil.getString(doc, "status"))
                .append("stockNo", VtuzxUtil.getString(doc, "stockNo"))
                .append("remark", VtuzxUtil.getString(doc, "remark"))
                .append("auditTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "auditTime")))
                .append("createTime", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(doc, "createTime")))
                .append("type",VtuzxUtil.getString(doc,"type"))
                .append("isPrint",VtuzxUtil.getString(doc,"isPrint"))
                .append("taskBillNo",VtuzxUtil.getString(doc,"taskBillNo"))
                .append("otherOutNo",VtuzxUtil.getString(doc,"otherOutNo"))
                .append("count", VtuzxUtil.getDouble(doc, "count")));
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getOtherInBillDetail(ObjectId _userId, String stockNo, String billNo) {
        Document otherInDoc = otherInDao.findOne(Criteria.where("billNo").is(billNo).and("stockNo").is(stockNo));
        String qtrkBillNo = VtuzxUtil.getString(otherInDoc, "billNo");
        String remark = VtuzxUtil.getString(otherInDoc,"remark");
        String createUserName = VtuzxUtil.getString(otherInDoc, "createUserName");
        String createTime = VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(otherInDoc, "createTime"));
        String stock = VtuzxUtil.getString(otherInDoc, "stockNo");
        String otherOutNo = VtuzxUtil.getString(otherInDoc, "otherOutNo");//其他出库单号
        double count = VtuzxUtil.getDouble(otherInDoc, "count");
        int boxCount = VtuzxUtil.getInt(otherInDoc, "boxCount");
        VtuzxMap header = new VtuzxMap("billNo", qtrkBillNo)
                .append("createUserName", createUserName)
                .append("createTime", createTime)
                .append("stockNo", stock)
                .append("otherOutNo", otherOutNo)
                .append("count", String.format("%.2f",count))
                .append("remark",remark)
                .append("boxCount", boxCount);

        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> otherInDetailItr = otherInDetailDao.findList(Criteria.where("billNo").is(billNo).and("stockNo").is(stockNo), null, 0, 0);
        while (otherInDetailItr.hasNext()) {
            Document otherInDetailDoc = otherInDetailItr.next();
            VtuzxMap otherInDetailMap = new VtuzxMap(otherInDetailDoc);
            String _id = VtuzxUtil.removeString(otherInDetailMap, IVtuzxConst.Key__id);
            String _createUserId = VtuzxUtil.removeString(otherInDetailMap, "_createUserId");
            double detailCount = VtuzxUtil.getDouble(otherInDetailMap,"count");
            otherInDetailMap.append("count",String.format("%.2f",detailCount));
            dataList.add(otherInDetailMap.append("_id", _id).append("_createUserId", _createUserId));
        }
        //获取当前任务时间添加任务编号
        Date otherCreateTime = VtuzxUtil.getObject(otherInDoc,"createTime");
        //把date转换成localdateTime获取当天开始时间和结束时间
        Instant instant = otherCreateTime.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        LocalDateTime localDateTime = instant.atZone(zoneId).toLocalDateTime();
        LocalDateTime startTime = localDateTime.with(LocalTime.MIN);
        LocalDateTime endTime = localDateTime.with(LocalTime.MAX);
        //再转化成String类型
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String localStartTime = startTime.format(formatter);
        String localEndTime = endTime.format(formatter);
        //根据任务编号的时间查询这一天的数据
        List<VtuzxMap> dayList = new ArrayList<>();
        Criteria cond = new Criteria();
        cond.and("createTime").gte(VtuzxUtil.parseDate(localStartTime)).lte(VtuzxUtil.parseDate(localEndTime));
        Iterator<Document> otherInItr = otherInDao.findList(cond, new Document("createTime", 1), 0, 0);
        while (otherInItr.hasNext()) {
            Document prdColDoc = otherInItr.next();
            VtuzxMap dayMap = new VtuzxMap(prdColDoc);
            dayList.add(dayMap);
        }
        //获取当前任务的序号
        int orderNum = 0;
        for (VtuzxMap map : dayList) {
            orderNum++;
            String taskBillNo = VtuzxUtil.getString(map, "billNo");
            if (billNo.equals(taskBillNo)) {
                break;
            }
        }
        header.append("orderNum",orderNum);
        return new VtuzxMap("header", header).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getOtherInBillDetailBox(ObjectId _userId, String _detailId) {
        Criteria cond = Criteria.where("_detailId").is(FastUtil.convertId(_detailId));
        List<VtuzxMap> dataList = new ArrayList<>();
        Iterator<Document> otherInDetailBoxItr = otherInDetailBoxDao.findList(cond, null, 0, 0);
        while (otherInDetailBoxItr.hasNext()) {
            Document otherInDetailBoxDoc = otherInDetailBoxItr.next();
            VtuzxMap boxMap = new VtuzxMap(otherInDetailBoxDoc);
            boxMap.remove(IVtuzxConst.Key_createTime);
            boxMap.remove(IVtuzxConst.Key_updateTime);
            boxMap.remove("_createUserId");
            boxMap.remove("createUserName");
            boxMap.remove("_updateUserId");
            boxMap.remove("updateUserName");
            boxMap.append("id", VtuzxUtil.removeString(boxMap, IVtuzxConst.Key__id));
            dataList.add(boxMap);
        }
        return new VtuzxMap(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public void uploadOtherColBill(ObjectId _userId, String userName, File file) throws Exception {
        List<VtuzxExcelSheet> sheets = VtuzxExcel.read(file);
        VtuzxExcelSheet sheet = sheets.get(0);
        int rowSize = sheet.rowSize();
        List<Map<String, Object>> newBillList = new ArrayList<>();
        String preMaterialNo = "";
        String preBatchNo = "";
        Map<String, Object> bill = null;
        for (int i = 1; i < rowSize; i++) {
            String materialNo = "";
            String materialName = "";
            String materialSpec = "";
            String batchNo = "";
            double otherCount = 0;
            String boxNo = "";
            double count = 0;
            String comment = "";
            int cellSize = sheet.row(i).cellSize();
            for(int ci = 0; ci < cellSize; ci++) {
                if (sheet.row(i).cell(ci).col() == 0) materialNo = sheet.row(i).cell(ci).strCellValue();
                if (sheet.row(i).cell(ci).col() == 1) materialName = sheet.row(i).cell(ci).strCellValue();
                if (sheet.row(i).cell(ci).col() == 2) materialSpec = sheet.row(i).cell(ci).strCellValue();
                if (sheet.row(i).cell(ci).col() == 3) batchNo = sheet.row(i).cell(ci).strCellValue();
                if (sheet.row(i).cell(ci).col() == 4) otherCount = sheet.row(i).cell(ci).doubleCellValue();
                if (sheet.row(i).cell(ci).col() == 5) boxNo = sheet.row(i).cell(ci).strCellValue();
                if (sheet.row(i).cell(ci).col() == 6) count = sheet.row(i).cell(ci).doubleCellValue();
                if (sheet.row(i).cell(ci).col() == 7) comment = sheet.row(i).cell(ci).strCellValue();
            }

            if (!materialNo.equals(preMaterialNo) || !batchNo.equals(preBatchNo)) {
                bill = new HashMap<>();
                newBillList.add(bill);
                bill.put("materialNo", materialNo);
                bill.put("materialName", materialName);
                bill.put("materialSpec", materialSpec);
//                bill.put("supplierNo", "");
//                bill.put("supplierName", "");
                bill.put("batchNo", batchNo);
                bill.put("otherCount", otherCount);
//                bill.put("produceDate", "");
//                bill.put("exp", "");
                List<Map<String, Object>> boxList = new ArrayList<>();
                bill.put("boxList", boxList);
            }
            List<Map<String, Object>> boxList = VtuzxUtil.getObject(bill, "boxList");
            boxList.add(new VtuzxMap("boxNo", boxNo).append("count", count).append("comment", comment));
            preMaterialNo = materialNo;
            preBatchNo = batchNo;
        }
        for(Map<String, Object> newBill: newBillList) {
            VtuzxMap res = saveOtherColBill(_userId, userName, newBill);
            String billNo = VtuzxUtil.getString(res, "billNo");
            auditOtherColBill(_userId, userName, billNo);
        }
    }

    @Override
    public VtuzxMap saveOtherColBill(ObjectId _userId, String userName, Map<String, Object> param) throws VtuzxException {
        // 获取用户信息
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
        String unit = "kg";
        String goodsType = "";
        if (!VtuzxUtil.isEmpty(materialDoc)) {
            unit = VtuzxUtil.getString(materialDoc, "fBaseUnitIdFName");
            goodsType = VtuzxUtil.getString(materialDoc, "goodsType");
        }
        Document doc = new Document();
        doc.append("materialNo", materialNo);
        doc.append("materialName", VtuzxUtil.getString(param, "materialName"));
        doc.append("materialSpec", VtuzxUtil.getString(param, "materialSpec"));
        doc.append("supplierNo", VtuzxUtil.getString(param, "supplierNo"));
        doc.append("supplierName", VtuzxUtil.getString(param, "supplierName"));
        doc.append("batchNo", VtuzxUtil.getString(param, "batchNo"));
        doc.append("produceDate", VtuzxUtil.getString(param, "produceDate"));
        doc.append("exp", VtuzxUtil.getInt(param, "exp"));
        doc.append("otherCount", VtuzxUtil.getDouble(param, "otherCount"));
        doc.append("remark", VtuzxUtil.getString(param, "remark"));
        // 计算总箱数和总称重
        List<Map<String, Object>> boxList = VtuzxUtil.getObject(param, "boxList");
        double total = 0;
        for(Map<String, Object> box: boxList) {
            double count = VtuzxUtil.getDouble(box, "count");
            total += count;
        }
        doc.append("count", total);
        doc.append("unit", unit);
        doc.append("boxCount", boxList.size());

        List<Document> detailList = new ArrayList<>();
        if (VtuzxUtil.isEmpty(billNo)) {
            billNo = IXqcConst.createBillNo(BillType.QTSH);
            _logger.info(String.format("新建单据号：%s", billNo));
            doc.append("billNo", billNo);
            doc.append("status", BillStatus.Save.toString());
            doc.append("_createUserId", _userId);
            doc.append("createUserName", userName);
            otherColDao.insertOne(doc);
            doc.append("colType", "otherCol").append("goodsType", goodsType);
            doc.remove("_id");
            doc.remove("createTime");
            doc.remove("updateTime");
            doc.append("colUserName", userName);
            doc.append("colTime", VtuzxUtil.formatYmdHmsF(new Date()));
            testRoomDao.insertOne(doc);
        } else {
            doc.append("_updateUserId", _userId);
            doc.append("updateUserName", userName);
            UpdateResult res = otherColDao.updateOne(Criteria.where("billNo").is(billNo).and("status").is(BillStatus.Save.toString()), doc);
            if (res.getModifiedCount() == 0) {
                throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
            }
            Iterator<Document> detailItr = otherColDetailDao.findList(Criteria.where("billNo").is(billNo), null, 0, 0);
            while(detailItr.hasNext()) {
                detailList.add(detailItr.next());
            }
        }
        List<ObjectId> _delIds = new ArrayList<>();
        List<Document> insertList = new ArrayList<>();
        for(Map<String, Object> box: boxList) {
            String boxNo = VtuzxUtil.getString(box, "boxNo");
            String comment = VtuzxUtil.getString(box, "comment");
            boolean exist = false;
            for(Document detail: detailList) {
                String boxNoDB = VtuzxUtil.getString(detail, "boxNo");
                if (boxNo.equals(boxNoDB)) {
                    otherColDetailDao.updateById(
                            detail.getObjectId(IVtuzxConst.Key__id),
                            new Document("count", VtuzxUtil.getDouble(box, "count"))
                                    .append("_updateUserId", _userId)
                                    .append("updateUserName", userName)
                                    .append("comment", comment)
                    );
                    exist = true;
                    detailList.remove(detail);
                    break;
                }
            }
            if (!exist) {
                insertList.add(new Document("count", VtuzxUtil.getDouble(box, "count"))
                        .append("unit", unit)
                        .append("billNo", billNo)
                        .append("boxNo", VtuzxUtil.getString(box, "boxNo"))
                        .append("comment", VtuzxUtil.getString(box, "comment"))
                        .append("inStock", false)
                        .append("_insertUserId", _userId)
                        .append("insertUserName", userName));
            }
        }
        for(Document detail: detailList) {
            _delIds.add(VtuzxUtil.getObject(detail, IVtuzxConst.Key__id));
        }
        _logger.info(String.format("删除单据分录行：%d", _delIds.size()));
        if (_delIds.size() > 0) {
            otherColDetailDao.deleteMany(Criteria.where(IVtuzxConst.Key__id).in(_delIds));
        }
        _logger.info(String.format("新建单据分录行：%d", insertList.size()));
        if (insertList.size() > 0) {
            otherColDetailDao.insertMany(insertList);
        }
        return new VtuzxMap("billNo", billNo);
    }

    @Override
    public void deleteOtherColBill(ObjectId _userId, String billNo) throws VtuzxException {
        DeleteResult res = otherColDao.deleteOne(Criteria.where("billNo").is(billNo).and("status").is(BillStatus.Save.toString()));
        if (res.getDeletedCount() == 0) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        otherColDetailDao.deleteMany(Criteria.where("billNo").is(billNo));
    }


    @Override
    public VtuzxMap auditOtherColBill(ObjectId _userId, String userName, String billNo) throws VtuzxException {
        Criteria cond = Criteria.where("billNo").is(billNo).and("status").is(BillStatus.Save.toString());
        Document updateDoc = new Document("status", BillStatus.Audit.toString());
        updateDoc.append("_auditUserId", _userId);
        updateDoc.append("auditUserName", userName);
        updateDoc.append("auditTime", new Date());
        UpdateResult res = otherColDao.updateOne(cond, updateDoc);
        if (res.getModifiedCount() == 0) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        return new VtuzxMap("status", BillStatus.Audit.toString());
    }

    @Override
    public VtuzxMap unauditOtherColBill(ObjectId _userId, String billNo) throws VtuzxException {
        Iterator<Document> otherColDetailItr = otherColDetailDao.findList(Criteria.where("perColBillNo").is(billNo).and("_insertUserId").is(_userId), null, 0, 0);
        while (otherColDetailItr.hasNext()) {
            Document otherColDetailDoc = otherColDetailItr.next();
            boolean inStock = VtuzxUtil.getBoolean(otherColDetailDoc, "inStock");
            if (inStock) {
                throw new VtuzxException("订单存在已入库的分录,不能进行反审操作");
            }
        }
        Criteria cond = Criteria.where("billNo").is(billNo).and("status").is(BillStatus.Audit.toString());
        Document updateDoc = new Document("$set", new Document("status", BillStatus.Save.toString()));
        updateDoc.append("$unset", new Document("_auditUserId", 1).append("auditUserName", 1).append("auditTime", 1));
        UpdateResult res = otherColDao.updateOneRedirect(cond, updateDoc);
        if (res.getModifiedCount() == 0) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        return new VtuzxMap("status", BillStatus.Save.toString());
    }

    @Override
    public VtuzxMap getOtherColMaterialByRfid(List<String> rfidList) {
        Iterator<Document> boxItr = otherColDetailDao.findList(Criteria.where("rfid").in(rfidList).and("inStock").ne(true), null, 0, 0);
        List<Document> boxList = new ArrayList<>();
        List<String> billNoList = new ArrayList<>();
        while(boxItr.hasNext()) {
            Document box = boxItr.next();
            String billNo = VtuzxUtil.getString(box, "billNo");
            boxList.add(box);
            if (!billNoList.contains(billNo)) {
                billNoList.add(billNo);
            }
        }
        if (VtuzxUtil.isEmpty(boxList)) {
            return new VtuzxMap(IVtuzxConst.Key_data, new ArrayList<>());
        }
        Iterator<Document> billItr = otherColDao.findList(Criteria.where("billNo").in(billNoList).and("status").is(BillStatus.Audit.toString()), null, 0, 0);
        VtuzxMap billMap = FastUtil.itr2Map(billItr, "billNo");
        for(int i = boxList.size() - 1; i >= 0; i--) {
            Document box = boxList.get(i);
            String billNo = VtuzxUtil.getString(box, "billNo");
            Document bill = VtuzxUtil.getObject(billMap, billNo);
            if (bill == null) {
                boxList.remove(i);
                continue;
            }
            if (bill.containsKey("count")) {
                bill.append("countTotal", VtuzxUtil.removeObject(bill, "count"));
            }
            box.putAll(bill);
            box.remove(IVtuzxConst.Key__id);
            box.remove(IVtuzxConst.Key_createTime);
            box.remove(IVtuzxConst.Key_updateTime);
            box.remove("auditTime");
            box.remove("_createUserId");
            box.remove("_updateUserId");
            box.remove("createUserName");
            box.remove("updateUserName");
            box.remove("auditUserName");
        }
        return new VtuzxMap(IVtuzxConst.Key_data, boxList);
    }

    @Override
    public VtuzxMap getOtherColMaterial(String boxNoKey) throws VtuzxException {
        String boxNo;
        if (boxNoKey.contains("|;")) {
            String[] boxValues = boxNoKey.split("\\|\\;");
            if (boxValues.length == 5) {
                String supplierNo = boxValues[0];
                String materialNo = boxValues[1];
                String batchNo = boxValues[2];
                String flowNo = boxValues[3];
                int count = Integer.parseInt(boxValues[4]);
                return getOtherColMaterial(boxNoKey, supplierNo, materialNo, batchNo, flowNo, count);
            }
            boxNo = boxValues[boxValues.length - 1];
        } else {
            boxNo = boxNoKey;
        }
        Document box = otherColDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
        if (box == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        boolean inStock = VtuzxUtil.getBoolean(box, "inStock");
        if (inStock) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_in_stock, boxNo);
        }
        String billNo = VtuzxUtil.getString(box, "billNo");
        Document bill = otherColDao.findOne(Criteria.where("billNo").is(billNo));
        if (bill == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        bill.append("countTotal", VtuzxUtil.removeObject(bill, "count"));
        if (!BillStatus.Audit.hit(VtuzxUtil.getString(bill, "status"))) {
            throw new VtuzxException(String.format("箱号的采购收货单[%s]未审核!", billNo));
        }
        VtuzxMap res = new VtuzxMap(box);
        res.putAll(bill);
        res.remove(IVtuzxConst.Key__id);
        res.remove(IVtuzxConst.Key_createTime);
        res.remove(IVtuzxConst.Key_updateTime);
        res.remove("auditTime");
        res.remove("_createUserId");
        res.remove("_updateUserId");
        res.remove("createUserName");
        res.remove("updateUserName");
        res.remove("auditUserName");
        return res;
    }

    @Override
    public VtuzxMap getOtherColMaterial(String boxNo, String supplierNo, String materialNo, String batchNo, String flowNo, int count) throws VtuzxException {
        VtuzxMap res = new VtuzxMap();
        Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
        if (materialDoc == null) {
            throw new VtuzxException("物料不存在");
        }
        Document supplierDoc = supplierDao.findOne(Criteria.where("fNumber").is(supplierNo));
        if (supplierDoc == null) {
            throw new VtuzxException("供应商不存在");
        }
        res.append("materialNo", materialNo);
        res.append("materialName", VtuzxUtil.getString(materialDoc, "fName"));
        res.append("materialSpec", VtuzxUtil.getString(materialDoc, "fSpecification"));
        res.append("unit", VtuzxUtil.getString(materialDoc, "fBaseUnitIdNumber"));
        res.append("supplierNo", supplierNo);
        res.append("supplierName", VtuzxUtil.getString(supplierDoc, "fName"));
        res.append("batchNo", batchNo);
        res.append("count", count);
        res.append("boxCount", 1);
        res.append("billNo", "");
        res.append("boxNo", boxNo);
        res.append("inStock", false);
        res.append("rfid", "");
        res.append("barcodeType", "BC");
//        "supplierName": "",
//        "res": true,
//        "batchNo": "20220602134141",
//        "materialSpec": "混等",
//        "count": 5.0,
//        "supplierNo": "",
//        "materialName": "鲜海参 滚子",
//        "unit": "jin",
        return res;
    }

    @Override
    public VtuzxMap getOtherColMaterialForBind(String boxNo) throws VtuzxException {
        Document boxDoc = otherColDetailDao.findOne(Criteria.where("boxNo").is(boxNo));
        if (boxDoc == null) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_exist, boxNo);
        }
        boolean inStock = VtuzxUtil.getBoolean(boxDoc, "inStock");
        if (inStock) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_in_stock, boxNo);
        }
        String billNo = VtuzxUtil.getString(boxDoc, "billNo");
        Document otherColDoc = otherColDao.findOne(Criteria.where("billNo").is(billNo));
        if (otherColDoc == null) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_exist, boxNo);
        }
        String status = VtuzxUtil.getString(otherColDoc, "status");
        if (!BillStatus.Audit.hit(status)) {
            throw new VtuzxException(IXqcConst.Msg_E_XQC_box_not_audit, boxNo);
        }
        return new VtuzxMap("materialNo", VtuzxUtil.getString(otherColDoc, "materialNo"))
                .append("materialName", VtuzxUtil.getString(otherColDoc, "materialName"))
                .append("materialSpec", VtuzxUtil.getString(otherColDoc, "materialSpec"))
                .append("batchNo", VtuzxUtil.getString(otherColDoc, "batchNo"))
                .append("unit", VtuzxUtil.getString(otherColDoc, "unit"))
                .append("count", VtuzxUtil.getDouble(boxDoc, "count"))
                .append("supplierName", VtuzxUtil.getString(otherColDoc, "supplierName"))
                .append("instockDate", VtuzxUtil.formatYmdHmsF(VtuzxUtil.getObject(otherColDoc, "createTime")))
                .append("produceDate", VtuzxUtil.getString(otherColDoc, "produceDate"))
                .append("exp", VtuzxUtil.getInt(otherColDoc, "exp"));
    }

    @Override
    public VtuzxMap getPrdInMaterialForBind(String boxNo) throws VtuzxException {
        return null;
    }

    @Override
    public VtuzxMap updateOtherInSeal(ObjectId userId, String name, Map<String, Object> param) {
        String billNo = VtuzxUtil.getString(param, "billNo");
        otherInDao.updateOneRedirect(Criteria.where("billNo").is(billNo), new Document("$set", new Document("isPrint", "seal")));
        return new VtuzxMap("isPrint", billNo);
    }

    @Override
    public VtuzxDownloadBean downloadOtherInDetail(VtuzxToken token, Map<String, Object> param) throws Exception {
        String stockNo = VtuzxUtil.getString(param, "stockNo");
        String billNo = VtuzxUtil.getString(param, "billNo");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String boxNo = VtuzxUtil.getString(param, "boxNo");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        String remark = VtuzxUtil.getString(param,"remark");
        String otherOutNo = VtuzxUtil.getString(param,"otherOutNo");
        String isPrint = VtuzxUtil.getString(param, "isPrint");
        String type = VtuzxUtil.getString(param,"type");
        List<String> createTime = VtuzxUtil.getObject(param, "createTime");
        List<VtuzxMap> dataList = new ArrayList<>();
        List<String> billNoList = new ArrayList<>();//单据编号集合
        Criteria cond = new Criteria();
        cond.and("count").ne(0);//数量等于零的不显示
        if (!VtuzxUtil.isEmpty(stockNo)) {
            cond.and("stockNo").regex(stockNo);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(type)) {
            cond.and("type").regex(type);
        }
        if(!VtuzxUtil.isEmpty(otherOutNo)){
            cond.and("otherOutNo").regex(otherOutNo);
        }
        if (!VtuzxUtil.isEmpty(isPrint)) {
            cond.and("isPrint").is(isPrint);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            String[] splitList = createUserName.split("，");
            if (splitList.length == 1) {
                cond.and("createUserName").regex(createUserName);
            } else {
                List<String> split = new ArrayList<>(Arrays.asList(splitList));//数组转list
                cond.and("createUserName").in(split);
            }
        }
        if (!VtuzxUtil.isEmpty(remark)){
            cond.and("remark").regex(remark);
        }
        if (!VtuzxUtil.isEmpty(createTime)) {
            cond.and("createTime").gte(VtuzxUtil.parseDate(createTime.get(0))).lte(VtuzxUtil.parseDate(createTime.get(1) + " 23:59:59"));
        }
        Iterator<Document> otherinItr = otherInDao.findList(cond,new Document("createTime",-1),0,0);
        Map<String,Object> statusMap = new HashMap<>();//key:单据编号，value;状态
        Map<String,Object> otherOutMap = new HashMap<>();//key :单据编号  value:出库单号
        while (otherinItr.hasNext()){
            Document otherDoc = otherinItr.next();
            String otherBillNo = VtuzxUtil.getString(otherDoc,"billNo");
            String otherOutBillNo = VtuzxUtil.getString(otherDoc,"otherOutNo");
            String status = VtuzxUtil.getString(otherDoc,"status");
            if (!billNoList.contains(otherBillNo)){
                billNoList.add(otherBillNo);
            }
            if ("audit".equals(status)){
                statusMap.put(otherBillNo,"审核");
            } else {
                statusMap.put(otherBillNo,"保存");
            }
            if(!VtuzxUtil.isEmpty(otherOutBillNo)){
                otherOutMap.put(otherBillNo,otherOutBillNo);
            }
        }
        List<Document> detailList = new ArrayList<>();
        List<String> stockNoList = new ArrayList<>();//仓库编号集合
        Iterator<Document> detailItr = otherInDetailDao.findList(Criteria.where("billNo").in(billNoList),new Document("createTime",-1),0,0);
        while (detailItr.hasNext()){
            Document detailDoc = detailItr.next();
            String otherStockNo = VtuzxUtil.getString(detailDoc,"stockNo");
            if (!stockNoList.contains(otherStockNo)){
                stockNoList.add(otherStockNo);
            }
            detailList.add(detailDoc);
        }
        //查询仓库名称
        VtuzxMap stockMap = new VtuzxMap();
        Iterator<Document> stockItr = stockDao.findList(Criteria.where("fNumber").in(stockNoList), null, 0, 0);
        while (stockItr.hasNext()) {
            Document stock = stockItr.next();
            String stockNumber = VtuzxUtil.getString(stock, "fNumber");
            String stockName = VtuzxUtil.getString(stock, "fName");
            stockMap.append(stockNumber, stockName);
        }
        for (Document otherDoc : detailList){
            String otherStockNo = VtuzxUtil.getString(otherDoc,"stockNo");
            String stockName = VtuzxUtil.getString(stockMap,otherStockNo);//仓库名称
            String otherBillNo = VtuzxUtil.getString(otherDoc,"billNo");
            String status = VtuzxUtil.getString(statusMap,otherBillNo);
            String otherOutBillNo = VtuzxUtil.getString(otherOutMap,otherBillNo);
            otherDoc.append("stockName",stockName);
            otherDoc.append("status",status);
            otherDoc.append("otherOutNo",otherOutBillNo);

        }
        String timestamp = new SimpleDateFormat("yyMMddHHmmss").format(new Date());

        List<VtuzxExcelSheet> sheets = new ArrayList<>();
        VtuzxExcelSheet sheet0 = new VtuzxExcelSheet(0, "其他入库详情");
        int col = 0;
        int row = 0;
        VtuzxExcelRow header0 = new VtuzxExcelRow(row++, new VtuzxArrayList<>(
                new VtuzxExcelCell(col++, "状态"),
                new VtuzxExcelCell(col++, "入库单号"),
                new VtuzxExcelCell(col++, "创建时间"),
                new VtuzxExcelCell(col++, "仓库"),
                new VtuzxExcelCell(col++, "仓位"),
                new VtuzxExcelCell(col++, "物料编码"),
                new VtuzxExcelCell(col++, "物料名称"),
                new VtuzxExcelCell(col++, "物料规格"),
                new VtuzxExcelCell(col++, "单位"),
                new VtuzxExcelCell(col++, "批次"),
                new VtuzxExcelCell(col++, "箱数"),
                new VtuzxExcelCell(col++, "重量"),
                new VtuzxExcelCell(col, "其他出库")
        ));
        sheet0.addRow(header0);
        for (Document detail : detailList) {
            col = 0;
            VtuzxExcelRow dataRow = new VtuzxExcelRow(row++, new VtuzxArrayList<>(
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "status")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "billNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.formatYmdHmF(VtuzxUtil.getObject(detail, "createTime"))),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "stockName")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "locationNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "materialNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "materialName")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "materialSpec")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "unit")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "batchNo")),
                    new VtuzxExcelCell(col++, VtuzxUtil.getString(detail, "boxCount")),
                    new VtuzxExcelCell(col++, new BigDecimal(VtuzxUtil.getString(detail, "count")).setScale(2, RoundingMode.HALF_UP).doubleValue()),
                    new VtuzxExcelCell(col, VtuzxUtil.getString(detail,"otherOutNo"))
            ));
            sheet0.addRow(dataRow);
        }

        sheet0.setColumnWidth(new VtuzxArrayList<>(
                new int[]{0, 200},
                new int[]{1, 200},
                new int[]{2, 200},
                new int[]{3, 300},
                new int[]{4, 200},
                new int[]{5, 200},
                new int[]{6, 150},
                new int[]{7, 150},
                new int[]{8, 150},
                new int[]{8, 150}
        ));

        sheets.add(sheet0);
        ByteArrayOutputStream stream = new ByteArrayOutputStream();
        VtuzxExcel.write(stream, sheets);
        return new VtuzxDownloadBean("其他入库详情" + timestamp + ".xlsx", stream);
    }

    @Override
    public VtuzxMap getOtherColBill(ObjectId _userId, Map<String, Object> param, int pageIndex, int pageSize) {
        String status = VtuzxUtil.getString(param, "status");
        String billNo = VtuzxUtil.getString(param, "billNo");
        boolean checkNoRfid = !VtuzxUtil.isEmpty(VtuzxUtil.getString(param, "isNoRfid"));
        boolean isNoRfid = VtuzxUtil.getBoolean(param, "isNoRfid");
        boolean isNoStockIn = VtuzxUtil.getBoolean(param, "isNoStockIn");
        String materialNo = VtuzxUtil.getString(param, "materialNo");
        String materialName = VtuzxUtil.getString(param, "materialName");
        String batchNo = VtuzxUtil.getString(param, "batchNo");
        String createUserName = VtuzxUtil.getString(param, "createUserName");
        List<String> createTime = VtuzxUtil.getObject(param, "createTime");
        List<String> auditTime = VtuzxUtil.getObject(param, "auditTime");

        Criteria cond = new Criteria();
//        if (checkNoRfid) {
//            cond.getCriteriaObject().append("$where", "this.boxCount " + (isNoRfid? "!=": "=") + " this.bindBoxCount");
//            cond.and("$where").is("this.boxCount " + (isNoRfid? "!=": "=") + " this.bindBoxCount");
//        }
        if (!VtuzxUtil.isEmpty(status)) {
            cond.and("status").is(status);
        }
        if (!VtuzxUtil.isEmpty(billNo)) {
            cond.and("billNo").regex(billNo);
        }
        if (!VtuzxUtil.isEmpty(createUserName)) {
            String[] splitList = createUserName.split("，");
            if (splitList.length == 1) {
                cond.and("createUserName").regex(createUserName);
            } else {
                List<String> split = new ArrayList<>(Arrays.asList(splitList));//数组转list
                cond.and("createUserName").in(split);
            }
        }
        if (!VtuzxUtil.isEmpty(materialNo)) {
            cond.and("materialNo").regex(materialNo);
        }
        if (!VtuzxUtil.isEmpty(materialName)) {
            cond.and("materialName").regex("^.*" + materialName + ".*$");
        }
        if (!VtuzxUtil.isEmpty(batchNo)) {
            cond.and("batchNo").is(batchNo);
        }
        if (!VtuzxUtil.isEmpty(createTime)) {
            cond.and("createTime").gte(VtuzxUtil.parseDate(createTime.get(0))).lte(VtuzxUtil.parseDate(createTime.get(1) + " 23:59:59"));
        }
        if (!VtuzxUtil.isEmpty(auditTime)) {
            cond.and("auditTime").gte(VtuzxUtil.parseDate(auditTime.get(0))).lte(VtuzxUtil.parseDate(auditTime.get(1) + " 23:59:59"));
        }
        if (!VtuzxUtil.isEmpty(VtuzxUtil.getString(param, "isNoStockIn"))) {
            Iterator<Document> colDetailItr = otherColDetailDao.findList(Criteria.where("inStock").ne(true), null, 0, 0);
            List<String> notInStockBillNoList = new ArrayList<>();
            while(colDetailItr.hasNext()) {
                Document colDetail = colDetailItr.next();
                String notInStockBillNo = VtuzxUtil.getString(colDetail, "billNo");
                if (!notInStockBillNoList.contains(notInStockBillNo)) {
                    notInStockBillNoList.add(notInStockBillNo);
                }
            }
            if (isNoStockIn) {
                cond.and("billNo").nin(notInStockBillNoList);
            } else {
                cond.and("billNo").in(notInStockBillNoList);
            }
        }
        VtuzxPage page = otherColDao.getPageList(cond.getCriteriaObject(), checkNoRfid, isNoRfid, pageIndex, pageSize);
        List<VtuzxMap> dataList = page.iterator(itr -> {
            VtuzxMap data = new VtuzxMap(itr);
            int exp = VtuzxUtil.getInt(data, "exp");
            int boxCount = VtuzxUtil.getInt(data, "boxCount");
            int bindBoxCount = VtuzxUtil.getInt(data, "bindBoxCount");
            Date date = VtuzxUtil.parseDate(VtuzxUtil.getObject(data, "produceDate"));
            String expDate;
            if (exp <= 0) {
                expDate = "";
            } else {
                expDate = VtuzxUtil.formatYmdF(VtuzxUtil.calcDate(date, Calendar.DAY_OF_MONTH, exp));
            }
            data.append("isNotRfid", boxCount - bindBoxCount);
            data.append("expDate", expDate);
            data.append("id", VtuzxUtil.removeString(data, IVtuzxConst.Key__id));
            data.append(IVtuzxConst.Key_createTime, VtuzxUtil.formatYmdHmF(VtuzxUtil.removeObject(data, IVtuzxConst.Key_createTime)));
            data.remove(IVtuzxConst.Key_updateTime);
            data.append("auditTime", VtuzxUtil.formatYmdHmF(VtuzxUtil.removeObject(data, "auditTime")));
            data.remove("_createUserId");
            data.remove("_updateUserId");
            data.remove("_auditUserId");
            return data;
        });
        return new VtuzxMap(IVtuzxConst.Key_total, page.total()).append(IVtuzxConst.Key_data, dataList);
    }

    @Override
    public VtuzxMap getOtherColBillDetail(ObjectId _userId, String billNo) throws VtuzxException {
        Document doc = otherColDao.findOne(Criteria.where("billNo").is(billNo));
        if (doc == null) {
            throw new VtuzxException(IVtuzxConst.Msg_E_target_not_exist);
        }
        VtuzxMap header = new VtuzxMap(doc);
//        header.append("billNo", VtuzxUtil.getObject(doc, "billNo"));
//        header.append("status", VtuzxUtil.getObject(doc, "status"));
//        header.append("materialNo", VtuzxUtil.getObject(doc, "materialNo"));
//        header.append("materialName", VtuzxUtil.getObject(doc, "materialName"));
//        header.append("materialSpec", VtuzxUtil.getObject(doc, "materialSpec"));
//        header.append("supplierNo", VtuzxUtil.getObject(doc, "supplierNo"));
//        header.append("supplierName", VtuzxUtil.getObject(doc, "supplierName"));
//        header.append("batchNo", VtuzxUtil.getObject(doc, "batchNo"));
//        header.append("produceDate", VtuzxUtil.getObject(doc, "produceDate"));
//        header.append("exp", VtuzxUtil.getObject(doc, "exp"));
//        header.append("purCount", VtuzxUtil.getObject(doc, "purCount"));
        String materialNo = VtuzxUtil.getString(header, "materialNo");
        Document materialDoc = materialDao.findOne(Criteria.where("fNumber").is(materialNo));
        String unitName = VtuzxUtil.getString(materialDoc, "fBaseUnitIdFName");
        header.append(IVtuzxConst.Key_createTime, VtuzxUtil.formatYmdHmF(VtuzxUtil.removeObject(header, IVtuzxConst.Key_createTime)));
        Iterator<Document> boxItr = otherColDetailDao.findList(Criteria.where("billNo").is(billNo), new Document("boxNo", 1), 0, 0);
        List<VtuzxMap> boxList = new ArrayList<>();
        while(boxItr.hasNext()) {
            Document boxDoc = boxItr.next();
            VtuzxMap otherColDetailMap = new VtuzxMap(boxDoc);
            otherColDetailMap.remove(IVtuzxConst.Key_createTime);
            otherColDetailMap.remove(IVtuzxConst.Key_updateTime);
            otherColDetailMap.remove("_createUserId");
            otherColDetailMap.remove("createUserName");
            otherColDetailMap.remove("_updateUserId");
            otherColDetailMap.remove("updateUserName");
            otherColDetailMap.append("id", VtuzxUtil.removeString(otherColDetailMap, IVtuzxConst.Key__id));
            otherColDetailMap.append("unitName", unitName);
            boxList.add(otherColDetailMap);
        }
        return new VtuzxMap("header", header).append("boxList", boxList);
    }

    @Override
    public VtuzxDownloadBean downloadOtherColBillBarcodeList(ObjectId _userId, List<String> billNoList) throws Exception {
        List<VtuzxMap> detailList = new ArrayList<>();
        for(String billNo: billNoList) {
            VtuzxMap detail = getOtherColBillDetail(_userId, billNo);
            detailList.add(detail);
        }
        return configService.downloadBillBarcode(BillType.CGSH, detailList);
    }

    @Override
    public VtuzxDownloadBean downloadOtherColBillBarcode(ObjectId _userId, String billNo) throws Exception {
        VtuzxMap detail = getOtherColBillDetail(_userId, billNo);
//        VtuzxMap header = VtuzxUtil.getObject(detail, "header");
//        List<VtuzxMap> boxList = VtuzxUtil.getObject(detail, "boxList");
        List<VtuzxMap> detailList = new ArrayList<>();
        detailList.add(detail);
        return configService.downloadBillBarcode(BillType.QTSH, detailList);
    }

    /**
     * 判断其他出入库的品项是否一样
     * @param otherInBillNo
     * @param otherOutBillNo
     * @return
     */
    private Boolean otherMaterial(String otherInBillNo,String otherOutBillNo){
        Iterator<Document> otherInItr = otherInDetailDao.findList(Criteria.where("billNo").is(otherInBillNo), null, 0, 0);
        Iterator<Document> otherOutItr = otherOutDetailDao.findList(Criteria.where("billNo").is(otherOutBillNo), null, 0, 0);
        List<Document> otherOutList = new ArrayList<>();
        List<Document> otherInList = new ArrayList<>();
        while (otherInItr.hasNext()){
            Document otherInDoc = otherInItr.next();
            otherInList.add(otherInDoc);
        }
        while (otherOutItr.hasNext()){
            Document otherOutDoc = otherOutItr.next();
            otherOutList.add(otherOutDoc);
        }

        Boolean flag = true;
        for (Document otherIn : otherInList){
            String materialNo = VtuzxUtil.getString(otherIn,"materialNo");
            for (Document otherOut : otherOutList){
                String outMaterialNo = VtuzxUtil.getString(otherOut,"materialNo");
                if (!materialNo.equals(outMaterialNo)){
                    flag = false;
                    break;
                }
            }
        }
        return flag;
    }

}
